package com.zh.config.fragment

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.webkit.JavascriptInterface
import android.webkit.SslErrorHandler
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.widget.EditText
import android.widget.FrameLayout
import androidx.core.widget.NestedScrollView
import com.blankj.utilcode.util.LogUtils
import com.zh.common.R
import com.zh.common.databinding.FragmentWebBinding
import com.zh.common.ktx.gotoAct
import com.zh.common.ktx.inflate
import com.zh.common.utils.EmptyUtils
import com.zh.common.view.web.IWebView
import com.zh.config.ZjConfig
import com.zh.config.dialog.DownloadDialog
import com.zh.config.utils.LinkCheckIsDown
import java.util.regex.Matcher
import java.util.regex.Pattern

/**
 * 嵌套两个webView。解决第一个页面点击后，下个页面返回被刷新问题
 *
 * 解决NestedScrollView嵌套WebView问题
 * WebView默认设置一些属性
 * 1、如果有播放视频，所在的Activity必须设置以下属性
 * android:configChanges="orientation|screenSize|keyboardHidden"
 * android:launchMode="singleTask"
 * android:theme="@style/Theme.AppCompat.Light.NoActionBar"
 * android:windowSoftInputMode="stateVisible|adjustResize"
 * 2、Scrollview嵌入WebView，解决在WebView中点击链接页面会向上滑动一下
 * android:descendantFocusability="blocksDescendants"
 */
class MyWebView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {

    var etContent: EditText? = null
    var loadOver: (() -> Unit)? = null
    var loadStart: (() -> Unit)? = null
    private val method = "android"
    private var activity: Activity? = null
    private var downloadDialog: DownloadDialog? = null
    private val urlList = mutableListOf<Pair<String, IWebView>>()
    private val imageUrls = mutableListOf<String?>()
    private var firstPageIsLoad = false
    private var clickIsATag = false
    private var cacheUrl = ""
    private val mJsInterface by lazy { IJavascriptInterface(imageUrls) }

    init {
        activity = context as Activity
    }

    fun loadUrl(url: String) {
        firstPageIsLoad = false
        val webView = addWeb(url)
        urlList.add(Pair(url, webView))
    }

    fun loadUrl(url: String, scrollView: NestedScrollView) {
        firstPageIsLoad = false
        val webView = addWeb(url, scrollView)
        urlList.add(Pair(url, webView))
    }

    /**
     * 加载富文本
     */
    fun loadDataWithBaseURL(data: String) {
        loadData(data)
    }

    fun loadDataWithBaseURL(data: String, scrollView: NestedScrollView) {
        loadData(data)
    }

    private fun loadData(data: String, scrollView: NestedScrollView? = null) {
        //得到图片
        imageUrls.clear()
        imageUrls.addAll(returnImageUrlsFromHtml(data))
        val view = FragmentWebBinding.bind(context.inflate(R.layout.fragment_web))
        addView(view.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
        scrollView?.let { view.webView.mScrollView = it }
        view.webView.let {
            val linkCss = "<head>" +
                    "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"> " +
                    "<style>html{padding:0px;} " +
                    "img{max-width:100% !important;height:auto;}" +
                    "video{max-width:100% !important;height:auto;background:#000;}" +
                    "div{max-width:100% !important;height:auto;}" +
                    "</style></head>"
            val html = "<html>$linkCss<body>$data</body></html>"
            it.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)
        }
        urlList.add(Pair("", view.webView))
    }

    private fun addWeb(url: String, scrollView: NestedScrollView? = null): IWebView {
        val view = FragmentWebBinding.bind(context.inflate(R.layout.fragment_web))
        addView(view.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
        view.apply {
            scrollView?.let {
                webView.mScrollView = scrollView
            }
            webView.loadUrl(url)
            webView.activity = activity
            webView.progress = progressBar
            webView.addJavascriptInterface(mJsInterface, method)
            webView.setMyWebViewClient(object : IWebView.MyWebViewClient {
                override fun onPageFinished(view: WebView, url: String) {
                    Log.e("webView", "onPageFinished->$url")
                    etContent?.setText(url)
                    webView.postDelayed({
                        setWebImageClick(view, method)
                    }, 500)
                    loadOver?.invoke()
                    if (!firstPageIsLoad) firstPageIsLoad = true
                    injectJavaScript(view)
                }

                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    Log.e("webView", "onPageStarted->$url")
                    etContent?.setText(url)
                    loadStart?.invoke()
                    clickIsATag = false
                }

                override fun shouldOverrideUrlLoading(
                    view: WebView?,
                    request: WebResourceRequest?
                ): Boolean {
                    Log.e("webView", "shouldOverrideUrlLoading->${request?.url}")
                    val url = request?.url.toString()
                    if (!arrayOf(
                            "http", "https", "file", "chrome", "data", "javascript", "about"
                        ).contains(request?.url?.scheme)
                    ) {
                        if (url.startsWith("market://")
                            || url.startsWith("appmarket://")
                            || url.startsWith("intent://")
                            || url.contains("play.google.com")
                        ) {//可以做提示
                            try {
                                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                                context?.startActivity(intent)
                            } catch (e: Exception) {
                                e.printStackTrace()
                            }
                        } else {//直接跳转
                            try {
                                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                                context?.startActivity(intent)
                            } catch (e: Exception) {
                                e.printStackTrace()
                            }
                        }
                        return true
                    }
                    val isDownload = LinkCheckIsDown.isDownloadLink(url)
                    if (isDownload) {
                        Log.e("webView", "拦截了url->${request?.url}")
                        if (downloadDialog == null || !downloadDialog!!.isShowing) {
                            downloadDialog = DownloadDialog(context)
                            downloadDialog?.showDialog(url)
                            return true
                        }
                    }
                    return if (!isDownload && firstPageIsLoad && urlList.size < 2
                        && urlList.find { it.first == request?.url.toString() } == null
                        && !clickIsATag && !url.endsWith(".exe")
                    ) {
                        Log.d("webView", "创建了新的WebView")
                        val webView = addWeb(url)
                        urlList.add(Pair(url, webView))
                        true
                    } else {
                        false
                    }
                }

                override fun onReceivedSslError(
                    view: WebView,
                    handler: SslErrorHandler,
                    error: SslError
                ) {

                }

                //拦截a标签的下载链接, ajax网络请求
                private fun injectJavaScript(webView: WebView) {
                    val js = "(function() {" +
                            "   var blobUrl = '';" +
                            "   var originalOpen = XMLHttpRequest.prototype.open;" +
                            "   XMLHttpRequest.prototype.open = function(method, url, async, user, password) {" +
                            "       this._method = method;" +
                            "       this._url = url;" +
                            "       originalOpen.apply(this, arguments);" +
                            "   };" +
                            "   var originalSend = XMLHttpRequest.prototype.send;" +
                            "   XMLHttpRequest.prototype.send = function(body) {" +
                            "       console.log('ajax request intercepted:'+ this._method, this._url);" +
                            "       originalSend.apply(this, arguments);" +
                            "       blobUrl = this._url" +
                            "   };" +
                            "   document.addEventListener('click', function(event) {" +
                            "       var target = event.target || {};" +
                            "       if (target.href) {" +
                            "           console.log('点击链接: ' + target + ' - ' + target.href);" +
                            "           if (target.href && target.href.indexOf('blob:') !== -1) {" +
                            "               console.log('文件名称: ' + target.download);" +
                            "               android.blobNameAndUrl(target.download, blobUrl);" +
                            "           }" +
                            "           if (target.tagName.toLowerCase() === 'a') {" +
                            "               android.clickIsATag(true);" +
                            "           } else {" +
                            "               android.clickIsATag(false);" +
                            "           }" +
                            "       }" +
                            "   }, true);" +
                            "})();"
                    webView.evaluateJavascript(js, null)
                }
            })
            webView.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
                LogUtils.e(
                    "webView", "DownloadListener url->$url",
                    userAgent, contentDisposition, mimetype, contentLength
                )
                if (downloadDialog == null || !downloadDialog!!.isShowing) {
                    if (EmptyUtils.isNotEmpty(contentDisposition)) {
                        var filename =
                            contentDisposition.substring(contentDisposition.indexOf("filename=") + 9)
                        filename = filename.replace("\"".toRegex(), "")
                        downloadDialog = DownloadDialog(context)
                        if (contentLength > 0) {
                            downloadDialog?.showDialog(
                                url, fileName = filename, fileSize = contentLength.toInt()
                            )
                        } else {
                            downloadDialog?.showDialog(url, fileName = filename)
                        }
                    } else if (url.startsWith("blob:http")) {
                        postDelayed({
                            downloadDialog = DownloadDialog(context)
                            downloadDialog?.showDialog(
                                mJsInterface.blobFileUrl,
                                fileName = mJsInterface.blobFileName,
                                fileSize = contentLength.toInt()
                            )
                        }, 10)
                    } else {
                        downloadDialog = DownloadDialog(context)
                        if (contentLength > 0) {
                            downloadDialog?.showDialog(url, fileSize = contentLength.toInt())
                        } else {
                            downloadDialog?.showDialog(url)
                        }
                    }
                }
            }
        }
        return view.webView
    }

    private fun hasGoBack(): Boolean {
        return try {
            urlList[urlList.size - 1].second.canGoBack()
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    private fun hasGoForward(): Boolean {
        return try {
            urlList[urlList.size - 1].second.canGoForward()
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    fun canGoBack(): Boolean {
        return try {
            if (urlList.size == 2) true
            else hasGoBack()
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    fun canGoForward(): Boolean {
        return try {
            return if (EmptyUtils.isNotEmpty(cacheUrl)) {
                true
            } else if (urlList.size == 2 && hasGoForward()) {
                true
            } else urlList.size == 1 && hasGoForward()
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    fun goReload() {
        try {
            urlList[urlList.size - 1].second.reload()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun goBack() {
        try {
            if (urlList.size == 2 && hasGoBack()) {
                urlList[urlList.size - 1].second.goBack()
                clickIsATag = false
            } else if (urlList.size == 2 && !hasGoBack()) {
                removeWebView()
                loadStart?.invoke()
                clickIsATag = false
            } else if (urlList.size == 1 && hasGoBack()) {
                urlList[urlList.size - 1].second.goBack()
                clickIsATag = false
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun goForward() {
        try {
            if (EmptyUtils.isNotEmpty(cacheUrl)) {
                val webView = addWeb(cacheUrl)
                urlList.add(Pair(cacheUrl, webView))
                cacheUrl = ""
            } else {
                urlList[urlList.size - 1].second.goForward()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        try {
            if (urlList.size > 0) {
                if (visibility == View.VISIBLE) {// View变为可见状态下的处理
                    urlList[urlList.size - 1].second.onResume()
                } else if (visibility == View.INVISIBLE || visibility == View.GONE) {// View变为不可见状态下的处理
                    urlList[urlList.size - 1].second.onPause()
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        removeAllViews()
    }

    fun ondestroy() {
        urlList.forEach {
            it.second.removeAllViews()
            try {
                it.second.destroy()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        urlList.clear()
    }

    fun onKeyDownLoad(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK && event?.action == KeyEvent.ACTION_DOWN) {
            val isLandscape =
                (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
            return if (isLandscape) {
                needRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                true
            } else if (urlList.size == 2 && hasGoBack()) {
                urlList[urlList.size - 1].second.goBack()
                loadStart?.invoke()
                clickIsATag = false
                true
            } else if (urlList.size == 2 && !hasGoBack()) {
                removeWebView()
                loadStart?.invoke()
                clickIsATag = false
                true
            } else if (urlList.size == 1 && hasGoBack()) {
                urlList[urlList.size - 1].second.goBack()
                loadStart?.invoke()
                clickIsATag = false
                true
            } else {
                activity?.finish()
                false
            }
        }
        return false
    }

    private fun removeWebView() {
        try {
            getWebUrl()?.let { cacheUrl = it }
            removeViewAt(childCount - 1)
            urlList[urlList.size - 1].second.removeAllViews()
            urlList[urlList.size - 1].second.destroy()
            urlList.removeAt(urlList.size - 1)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    inner class IJavascriptInterface {

        private var imageUrls: MutableList<String?> = mutableListOf()
        var blobFileName = ""
        var blobFileUrl = ""

        constructor()

        constructor(urls: MutableList<String?>) {
            imageUrls = urls
        }

        @JavascriptInterface
        fun clickIsATag(isATag: Boolean) {
            Log.d("webView", "拦截a标签点击事件 -> $isATag")
            clickIsATag = isATag
        }

        @JavascriptInterface
        fun blobNameAndUrl(name: String, url: String) {
            blobFileName = name
            blobFileUrl = url
        }

        //java回调js代码，不要忘了@JavascriptInterface这个注解，不然点击事件不起作用
        @JavascriptInterface
        fun openImage(img: String, pos: Int) {
            val arrayList = ArrayList<String?>()
            for (item in imageUrls) {
                arrayList.add(item)
            }
            //实现自己的图片浏览页面
            gotoAct(ZjConfig.Routes.LOOK_BIG_IMAGE, true) {
                putStringArrayList("imageUrls", arrayList)
                putInt("pos", pos)
            }
        }
    }

    private fun needRequestedOrientation(orientation: Int) {
        LogUtils.e("needRequestedOrientation: $orientation")
        activity?.requestedOrientation = orientation
    }

    /**
     * 设置网页中图片的点击事件
     * 视频默认播放到0.1秒来当做封面图
     * @param view
     */
    private fun setWebImageClick(view: WebView, method: String) {
        /*val jsCode = "javascript:(function(){" +
                "var imgs=document.getElementsByTagName(\"img\");" +
                "for(var i=0;i<imgs.length;i++){" +
                "   imgs[i].pos = i;" +
                "   imgs[i].onclick=function(){" +
                "       window." + method + ".openImage(this.src,this.pos);" +
                "   }" +
                "}" +
                "var videos = document.getElementsByTagName('video');" +
                "for (var i = 0; i < videos.length; i++) {" +
                "var video = videos[i];" +
                "    (function(i) {" +
                "        video.currentTime = 0.1;" +
                "        video.addEventListener('seeked', function() {" +
                "            var canvas = document.createElement('canvas');" +
                "            canvas.width = video.videoWidth;" +
                "            canvas.height = video.videoHeight;" +
                "            canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);" +
                "            var dataURL = canvas.toDataURL('image/png');" +
                "            video.poster = dataURL;" +
                "            video.pause();" +
                "        });" +
                "    })(i);" +
                "   }" +
                "})()"
        view.loadUrl(jsCode)*/
    }

    fun getWebName(): String? {
        return urlList[urlList.size - 1].second.webpageName
    }

    fun getWebIcon(): String? {
        return urlList[urlList.size - 1].second.webpageIcon
    }

    fun getWebUrl(): String? {
        return urlList[urlList.size - 1].second.url
    }

    fun getWebView(): IWebView {
        return urlList[urlList.size - 1].second
    }

    /**
     * 找到html中所有的图片url
     * @param htmlCode
     * @return
     */
    private fun returnImageUrlsFromHtml(htmlCode: String): MutableList<String?> {
        val imageSrcList = mutableListOf<String?>()
        val p = Pattern.compile(
            "<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\u000c>]+(\\.jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\.jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic|\\b)\\b)[^>]*>",
            Pattern.CASE_INSENSITIVE
        )
        val m: Matcher = p.matcher(htmlCode)
        var quote: String? = null
        var src: String? = null
        while (m.find()) {
            quote = m.group(1)
            src = if (quote == null || quote.trim { it <= ' ' }.isEmpty()) m.group(2)
                .split("//s+".toRegex()).dropLastWhile { it.isEmpty() }
                .toTypedArray()[0] else m.group(2)
            imageSrcList.add(src)
        }
        return if (imageSrcList.size == 0) mutableListOf()
        else imageSrcList
    }
}